<template>
  <section class="wrap animated fadeIn" @click.self="$emit('cancel')" :class="{hide: !display}">
    <div class="content animated fadeInUp">
      <header>
        <a class="left" @click="$emit('cancel')">取消</a>
        <strong>请选择日期</strong>
        <a v-if="!autoComplete" class="right" @click="confirm">确认</a>
      </header>
      <div class="week-text box">
        <div v-for="(text, i) in weekTexts"
          class="box-f1 tx-c"
          :key="i"
          :style="{color: mondayFirst
            ? i == 5 || i == 6 ? 'tomato' : ''
            : i == 0 || i == 6 ? 'tomato' : ''}">{{text}}</div>
      </div>
      <main ref="dateScroll">
        <section class="month" v-for="(item, i) in months" :key="i">
          <header class="month-title" :data-month="item.month">{{item.year}}年 {{item.month}}月</header>
          <div class="day-wrap">
            <div class="day"
              v-for="(day, j) in item.days" :key="j"
              :style="{'background-color': day.custom&&day.custom.bgcolor}"
              :class="{'disabled': day.disabled, 'active': day.active, 'select': day.begin || day.end, 'begin': day.begin}"
              @click="selectOne(day)">
              <!-- {{showTips(day)}} -->
              <div class="tips" v-if="showTips(day)">请选择结束时间</div>
              <span v-if="day.custom" :class="{rest: day.custom.highlight}">{{day.custom.text}}</span>
              <span v-else>&nbsp;</span>
              <span class="number" :class="{restday: day.restday, rest: day.rest, workday: day.workday}">{{day.text}}</span>
              <span>{{day.begin ? beginningText : day.end ? endText: '&nbsp;'}}</span>
            </div>
          </div>
        </section>
      </main>
    </div>
  </section>
</template>

<script>
import { getTop } from '@/assets/js/common'
/* eslint-disable */
class DateHelper {
  constructor () {}
  get year () {
    return new Date().getFullYear()
  }
  get month () {
    return new Date().getMonth() + 1
  }
  get day () {
    return new Date().getDate()
  }
  get date () {
    return `${this.year}-${this.month}-${this.day}`
  }
}
export default {
  props: {
    // 单选
    single: {
      type: Boolean,
      default () { return false }
    },
    // 自动完成
    autoComplete: {
      type: Boolean,
      default () { return false }
    },
    // 显示状态
    display: {
      type: Boolean,
      default () { return false }
    },
    // 是否周一为第一天
    mondayFirst: {
      type: Boolean,
      default () { return false }
    },
    // 允许反向选择日期
    reverseSelect: {
      type: Boolean,
      default () { return false }
    },
    // 自定义节假日
    restday: {
      type: Array,
      default () { return [] }
    },
    // 自定义补班日
    workday: {
      type: Array,
      default () { return [] }
    },
    // 加载日历的范围，单位为月
    displayRange: {
      type: Array,
      default () { return [-3, 3] }
    },
    // 可自定义显示开始日期
    // 默认为当月当日
    displayRangeStart: {
      type: String,
      default () { return new DateHelper().date }
    },
    // 可选择的开始日期
    selectRangeStart: {
      type: String,
      default () { return new DateHelper().date }
    },
    // 可选择的结束日期
    selectRangeEnd: {
      type: String,
      default () { return '2020-12-31' }
    },
    // 自定义数据
    custom: {
      type: Array,
      default () { return [] }
    },
    // 选择开头自定义文本
    beginningText: {
      type: String,
      default () { return '开始' }
      // default () { return '开始' }
    },
    // 选择末尾自定义文本
    endText: {
      type: String,
      default () { return '结束' }
      // default () { return '结束' }
    }
  },
  data () {
    return {
      months: [],
      firstTime: true,
      firstSelectDay: {},
      lastSelectDay: {},
      rangeList: [],
      customIndex: 0,
      range: []
    }
  },
  computed: {
    weekTexts () {
      const arrTexts = ['日', '一', '二', '三', '四', '五', '六']
      // 中国习惯周一为第一天
      if (this.mondayFirst) arrTexts.push(arrTexts.shift())
      return arrTexts
    },
    $date () {
      return new DateHelper()
    },
    mIndexBegin () {
      return this.months.findIndex(v => v.year === this.firstSelectDay.year && v.month === this.firstSelectDay.month)
    },
    mIndexEnd () {
      return this.months.findIndex(v => v.year === this.lastSelectDay.year && v.month === this.lastSelectDay.month)
    }
  },
  watch: {
    restday () {
      const vm = this
      if (this.restday.length) {
        this.deconstruction((date) => {
          this.restday.forEach(restday => {
            const restdate = new Date(restday)
            const [y, m, d] = [restdate.getFullYear(), restdate.getMonth() + 1, restdate.getDate()]
            if (y === date.year && m === date.month && d === date.day) {
              vm.$set(date, 'rest', true)
              vm.$set(date, 'restday', true)
            }
          })
        })
      }
    },
    workday () {
      const vm = this
      if (this.workday.length) {
        this.deconstruction((date) => {
          this.workday.forEach(workday => {
            const workdate = new Date(workday)
            const [y, m, d] = [workdate.getFullYear(), workdate.getMonth() + 1, workdate.getDate()]
            if (y === date.year && m === date.month && d === date.day) {
              vm.$set(date, 'rest', false)
              vm.$set(date, 'workday', true)
            }
          })
        })
      }
    },
    custom () {
      this.setcustom()
    }
  },
  created () {
    const months = []
    const [Y, M] = this.displayRangeStart.split('-').map(Number)
    const [Ys, Ms, Ds] = this.selectRangeStart.split('-').map(Number)
    const [Ye, Me, De] = this.selectRangeEnd.split('-').map(Number)
    let [year, month] = [Y, M]
    let customIndex = 0
    // console.log()
    // 循环出月份
    for (let i = this.displayRange[0]; i < this.displayRange[1]; i++) {
      // 满 13月进 1年
      if (M + i > 12) {
        year = Y + 1
        month = M + i - 12
      } else if (M + i < 0) {
        year = Y - 1
        month = M + i + 12
      } else {
        month = M + i
      }
      const days = [] // 每一天的数据对象会放入该数组
      // 通过占位把 1号排到实际的星期位置
      // 默认周日开头情况下，今天是星期几，就需要几个占位符
      // 周日为 0，不用处理
      let placeholder = new Date(year, month - 1, 1).getDay()
      // 如果是周一开头，把占位符往前移一天
      // 周日为 0，需处理成 7-1
      if (this.mondayFirst) placeholder = placeholder === 0 ? 6 : placeholder - 1
      for (let j = 0; j < placeholder; j++) {
        customIndex++
        days.push({})
      }
      // 得到当月总天数
      const daySum = new Date(year, month, 0).getDate()
      // 循环出每一天
      for (let day = 1; day <= daySum; day++) {
        const obj = {} // 存放的数据将会在 template中用到
        obj.year = year
        obj.month = month
        obj.day = day
        obj.date = `${year}-${month}-${day}`
        obj.odate = `${year}-${ month > 9 ? month : '0' + month}-${ day > 9 ? day : '0' + day}` // 补0的日期格式
        // 显示“今天”或者几号
        obj.text = year === this.$date.year && month === this.$date.month && day === this.$date.day ? '今天' : day
        // 获取星期几，判断周末
        const weekday = new Date(year, month - 1, day).getDay()
        const weekend = weekday === 6 || weekday === 0
        // 判断是否禁用状态
        // 同时在非禁用状态下，才处理周末
        if (year < Ys || year > Ye) {
          // obj.disabled = true
        } else if (year === Ys) {
          if (month < Ms || month > Me) {
            // obj.disabled = true
          } else if (month === Ms) {
            if (day < Ds || day > De) {
              // obj.disabled = true
            } else {
              obj.rest = day > Ds && weekend
              if (day === Ds) this.customIndex = customIndex
            }
          } else {
            obj.rest = weekend
          }
        } else {
          obj.rest = weekend
        }
        // 自定义休息日
        if (this.restday.length) {
          this.restday.forEach(date => {
            if (date === obj.date) obj.restday = obj.rest = true
          })
        }
        // 自定义工作日
        if (this.workday.length) {
          this.workday.forEach(date => {
            if (date === obj.date) {
              obj.workday = true
              obj.rest = false
            }
          })
        }
        customIndex++
        days.push(obj)
        // 结束循环每天
      }
      months.push({ year, month, days })
      // 结束循环每月
    }
    this.months = months
    console.log('months>>>', months)
    this.setcustom()
  },
  methods: {
    showTips (item) {
      // console.log(item)
      if (item.odate === this.firstSelectDay.odate && !this.firstTime) {
        return true
      } else {
        return false
      }
    },
    selectOne (tar, isInit) {
      this.months.forEach((item, index) => {
        item.days.forEach((item1, index1) => {
          if (tar.odate === item1.odate) {
            item1.begin = tar.begin
            item1.end = tar.end
            tar = this.months[index].days[index1]
          }
        })
      })
      const { disabled, custom, text } = tar
      // 点击1号之前的空白区域
      if (!tar.text) { return false }
      // 点击禁用的
      if (disabled) { return false }
      // 点击自定义禁用的，能够捕获事件
      if (custom && custom.disabled) {
        this.$emit('selectDisabled', tar)
        return false
      }
      if (this.single) {
        this.$set(this.lastSelectDay, 'begin', false)
        // 选中当前
        this.firstSelectDay = tar
        this.$set(tar, 'begin', true)
        // 记录第一次值
        this.lastSelectDay = this.firstSelectDay
        this.confirm()
      } else {
        // 第一次点击
        if (this.firstTime) {
          this.firstTime = false // 设置下一次点击为第二次
          // 清空之前选择
          if (this.mIndexBegin > -1 && this.mIndexEnd > -1) {
            for (let i = this.mIndexBegin; i <= this.mIndexEnd; i++) {
              this.months[i].days.forEach(day => {
                if (this.getTimestamp(day) === this.getTimestamp(this.firstSelectDay)) this.$set(day, 'begin', false)
                if (this.getTimestamp(day) > this.getTimestamp(this.firstSelectDay) && this.getTimestamp(day) < this.getTimestamp(this.lastSelectDay)) this.$set(day, 'active', false)
                if (this.getTimestamp(day) === this.getTimestamp(this.lastSelectDay)) this.$set(day, 'end', false)
              })
            }
          }
          // 选中当前
          this.firstSelectDay = tar
          this.$set(tar, 'begin', true)
        } else { // 第二次点击
          // 第二次点击和第一次点击相同
          if (this.getTimestamp(tar) === this.getTimestamp(this.firstSelectDay)) {
            this.firstTime = true
            this.$set(tar, 'begin', false)
            this.firstSelectDay = tar
            this.lastSelectDay = tar
            this.confirm()
            return false
          }
          // 在第一次点击之前
          if (this.getTimestamp(tar) < this.getTimestamp(this.firstSelectDay)) {
            this.firstTime = true
            if (this.reverseSelect) {
              // 记录第一次值
              const F = this.firstSelectDay
              // 交换值
              this.lastSelectDay = F
              this.firstSelectDay = tar
              // 将中间日期设为被选状态
              this.chooseRange()
                .then(({ range, activeDays }) => {
                  this.firstTime = true
                  // 取消上一次选中
                  this.$set(F, 'begin', false)
                  // 按交换后的值设置开头和结尾
                  this.$set(this.firstSelectDay, 'begin', true)
                  this.$set(this.lastSelectDay, 'end', true)
                  activeDays.forEach(date => this.$set(date, 'active', true))
                  this.range = range
                  if (this.autoComplete) this.confirm()
                })
                .catch(date => {
                  this.firstTime = false
                  // 初始点击逻辑值，使下次点击重新判断是否反选
                  this.firstSelectDay = F
                  this.lastSelectDay = {}
                  this.$emit('selectDisabled', date)
                })
            } else {
              // 取消上一次选中
              this.$set(this.firstSelectDay, 'begin', false)
              // 选中本次点击
              this.$set(tar, 'begin', true)
              this.firstSelectDay = tar
              // 将下一次点击设为第二次
              this.firstTime = false
            }
          } else {
            // 选中当前日期作为结尾
            this.lastSelectDay = tar
            // 将中间日期设为被选状态
            this.chooseRange()
              .then(({ range, activeDays }) => {
                this.firstTime = true
                this.$set(tar, 'end', true)
                activeDays.forEach(date => this.$set(date, 'active', true))
                this.range = range
                if (this.autoComplete) this.confirm()
              })
              .catch(date => {
                this.firstTime = false
                this.$emit('selectDisabled', date)
              })
          }
        }
      }
      // 滚动到开始时间
      if (isInit) {
        if (window.timer) clearTimeout(window.timer)
        window.timer = setTimeout(() => {
          let $begin = document.getElementsByClassName('select')[0]
          if ($begin) {
            // console.log($begin, this.$refs.dateScroll, getTop($begin, this.$refs.dateScroll))
            this.$refs.dateScroll.scrollTop = getTop($begin, this.$refs.dateScroll)
          }
        }, 100)
      }
    },
    getTimestamp (tar) {
      return new Date(tar.year, tar.month - 1, tar.day).getTime()
    },
    chooseRange () {
      return new Promise((resolve, reject) => {
        if (this.mIndexBegin > -1 && this.mIndexEnd > -1) {
          let range = []
          const activeDays = []
          for (let i = this.mIndexBegin; i <= this.mIndexEnd; i++) {
            range = range.concat(this.months[i].days.filter(date => {
              if (this.getTimestamp(date) > this.getTimestamp(this.firstSelectDay)
                && this.getTimestamp(date) < this.getTimestamp(this.lastSelectDay)) {
                if (date.custom && date.custom.disabled) {
                  reject(date)
                } else {
                  activeDays.push(date) // 不直接设置为激活状态，先存起来，交由外部处理。如果没有disabled才设置
                  return date
                }
              }
            }))
          }
          resolve({ range, activeDays })
        } else {
          resolve(new Array())
        }
      })
    },
    confirm () {
      console.log({ start: this.firstSelectDay, end: this.lastSelectDay, range: this.range })
      this.$emit('select', { start: this.firstSelectDay, end: this.lastSelectDay, range: this.range })
    },
    deconstruction (callback) {
      this.months.forEach(month => {
        month.days.forEach(date => {
          callback(date)
        })
      })
    },
    setcustom () {
      // 自定义数据
      if (this.custom.length) {
        // 将months里的days连接成一个普通的一维数组
        let days = []
        this.months.forEach(v => days = days.concat(v.days))
        // 从记录的index位置开始遍历日期，从0开始遍历自定义数组
        for (let i = this.customIndex, j = 0; j < this.custom.length; i++, j++) {
          const v = days[i]
          const data = this.custom[j]
          // 跳过1号之前的
          if (v.text && data) {
            const type = typeof data
            if (type === 'string') v.custom = { text: data }
            else if (type === 'object') v.custom = data
            else throw `custom数组每项的类型应该是String或Object，但是得到的是${type}`
          }
        }
      }
    }
  }
}
</script>

<style lang="scss" scoped>
@import '../assets/css/config';
@import '../assets/css/mixins';
.wrap{
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0,0,0,.66);
  transition: transform .5s ease-out;
  z-index: 88;
  &.hide{
    transform: translateY(100%)
  }
}
.content{
  position: absolute;
  bottom: 0;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 75%;
  background-color: white;
  text-align: center;
  >header{
    padding: .3rem;
    text-align: center;
    border-bottom:1px solid $borderColor;
    >a{
      position: absolute;
      font-size: .32rem;
      &.left{
        color:#666;
        left: .3rem;
      }
      &.right{
        color:$themeColor;
        right: .3rem;
      }
    }
  }
  .week-text{
    border-bottom:1px solid #DDD;
    padding:.2rem 0;
  }
  main{
    flex: 1;
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
    position:relative;
    .month{
      >header{
        // position: sticky;
        // top: 0;
        font-size:.3rem;
        padding: .2rem;
        background-color: #eee;
        z-index: 1;
      }
      .day-wrap{
        display: flex;
        flex-wrap: wrap;
        .day{
          display: flex;
          flex-direction: column;
          justify-content: center;
          position: relative;
          width: 14.28%;
          height:1.07rem;
          transition: all .3s;

          &.disabled{
            color: #BBB;
            >span{
              color: #BBB!important;
            }
          }
          &.select{
            color: white;
            background-color: deepskyblue;
            box-shadow: none;
            >span{
              color: white!important;
            }
          }
          &.active{
            background-color: lightblue;
            box-shadow: none;
          }
          .tips{
            position:absolute;
            top:-1rem;
            background-color: rgba(0,0,0,.7);
            width:2rem;
            font-size:.28rem;
            left:-.6rem;
            border-radius:.1rem;
            padding:.2rem;
            z-index:2;
            &:after{
              content: '';
              position: absolute;
              bottom:-.2rem;
              left:45%;
              border-left: .15rem solid transparent;
              border-right: .15rem solid transparent;
              border-top: .2rem solid rgba(0,0,0,.7);
            }
          }
          span{
            font-size: .22rem;
            &.number{
              font-size: .3rem;
              padding:.05rem 0;
            }
            &.rest{
              color: tomato;
            }
            &.restday:before{
              content: '休';
              position: absolute;
              top: 0.15rem;
              left: .45rem;
              font-size: .22rem;
            }
            &.workday:before{
              content: '班';
              position: absolute;
              top: 0.15rem;
              left: .45rem;
              font-size: .22rem;
              color: inherit;
            }
          }
        }
      }
    }
  }
}
</style>
